﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SKYPE4COMLib;
using SkypeStudio.Controls.Model;
using System.ComponentModel.Composition;
using System.Collections.ObjectModel;

namespace SkypeStudio.Controls.Services
{
    public enum SkypeProcessAttachStatus
    {
        apiAttachUnknown = -1,
        apiAttachSuccess = 0,
        apiAttachPendingAuthorization = 1,
        apiAttachRefused = 2,
        apiAttachNotAvailable = 3,
        apiAttachAvailable = 4,
    }

    public interface ISkypeInstanceMessage
    {
        event Action<Model.ChatMessage> MessageReceived;

        event Action<Model.ChatMessage> MessageSending;

        event Action<Model.ChatMessage> MessageSent;

        void SendMessage(string handle, string sendText);

        void SendMessage(Contact user, string sendText);

        void SendMessage(Model.Chat chat, string sendText);
    }

    public interface ISkypeProcessAttachStatus
    {
        SkypeProcessAttachStatus SkypeProcessAttachStatus { get; }

        event Action<SkypeProcessAttachStatus> SkypeProcessAttachStatusChanged;
    }

    public interface ISkypeApplicationService : ISkypeProcessAttachStatus, ISkypeInstanceMessage, IDisposable
    {
        ObservableCollection<SkypeStudio.Controls.Model.Chat> Chats { get; set; }
        event Action<Contact> ContactOnlineStatusChanged;

        IEnumerable<SkypeStudio.Controls.Model.Chat> GetChatList();

        IEnumerable<Contact> GetContactList();

        void ClientShutdown();

        void ClientStart();

        bool IsClientRunning { get; }

        void OpendAddContactDialog();

        void OpendSearchFriendDialog();

        void OpendShareFileDialog();

        Model.Chat CreateChat(Contact contact);

        Contact CurrentUSer { get; }
    }

    [Export(typeof(ISkypeApplicationService))]
    public class SkypeApplicationService : ISkypeApplicationService
    {
        #region Event
        public event Action<Model.ChatMessage> MessageReceived;

        public event Action<Model.ChatMessage> MessageSending;

        public event Action<Model.ChatMessage> MessageSent;

        public event Action<Contact> ContactOnlineStatusChanged;

        #endregion

        private ObservableCollection<SkypeStudio.Controls.Model.Chat> _Chats;

        private ObservableCollection<SkypeStudio.Controls.Model.Chat> _ObservableChatList;
        private SKYPE4COMLib.Skype _Skype;

        [ImportingConstructor]
        public SkypeApplicationService()
            : this(new SkypeClass())
        {
        }

        public SkypeApplicationService(SKYPE4COMLib.Skype skype)
        {
            _Skype = skype;
        }

        public ObservableCollection<SkypeStudio.Controls.Model.Chat> Chats
        {
            get
            {
                if (_Chats == null)
                {
                    //SkypeStudio.Controls.Model
                    _Chats = new ObservableCollection<SkypeStudio.Controls.Model.Chat>();
                    
                    foreach (SKYPE4COMLib.Chat item in _Skype.RecentChats)
                    {
                        _Chats.Add(
                            new SkypeStudio.Controls.Model.Chat()
                            {
                                ChatName = item.Name,
                                Members = new ObservableCollection<Contact>(item.Members.OfType<SKYPE4COMLib.User>().Select(o => o.ToContact())),
                                ChatMessages = new ObservableCollection<SkypeStudio.Controls.Model.ChatMessage>(item.RecentMessages.OfType<SKYPE4COMLib.ChatMessage>()
                                                    .Select(o => new SkypeStudio.Controls.Model.ChatMessage() { Message = o.Body, User = o.Sender.ToContact() })),
                                CurrentUser = this.CurrentUSer,
                            });
                    }
                }

                return _Chats;
            }
            set
            {
                _Chats = value;
            }
        }
        public bool IsClientRunning
        {
            get { return _Skype.Client.IsRunning; }
        }

        public void ClientStart()
        {
            if (!IsClientRunning)
            {
                _Skype.Client.Start(true, false);
            }

            try
            {
                ((_ISkypeEvents_Event)_Skype).ConnectionStatus += SkypeApplicationServiceConnectionStatus;
                ((_ISkypeEvents_Event)_Skype).AttachmentStatus += SkypeApplicationServiceAttachmentStatus;
                _Skype.MessageStatus += SkypeMessageStatusChanged;
                _Skype.OnlineStatus += SkypeOnlineStatusChanged;

                _Skype.Attach();
            }
            catch (System.Runtime.InteropServices.COMException comEx)
            {
                // The user have not log in yet. The user should login from Skype directly.
            }
        }

        void SkypeOnlineStatusChanged(User pUser, TOnlineStatus status)
        {
            var c = pUser.ToContact();
            c.OnlineStatus = (OnlineStatus)(int)status;
            OnContactOnlineStatusChanged(c);
        }

        void SkypeMessageStatusChanged(SKYPE4COMLib.ChatMessage pMessage, TChatMessageStatus status)
        {
            if (status == TChatMessageStatus.cmsReceived)
            {
                OnMessageReceived(new Model.ChatMessage() {   ChatName =pMessage.ChatName, User = pMessage.Sender.ToContact(), Message = pMessage.Body });
            }
            else if (status == TChatMessageStatus.cmsSending)
            {
                OnMessageSending(new Model.ChatMessage() { ChatName = pMessage.ChatName, User = pMessage.Sender.ToContact(), Message = pMessage.Body });
            }
            else if (status == TChatMessageStatus.cmsSent)
            {
                OnMessageSent(new Model.ChatMessage() { ChatName = pMessage.ChatName, User = pMessage.Sender.ToContact(), Message = pMessage.Body });
            }
        }

        void SkypeApplicationServiceAttachmentStatus(TAttachmentStatus status)
        {
            OnSkypeProcessAttachStatusChanged((SkypeProcessAttachStatus)(int)status);
        }

        void SkypeApplicationServiceConnectionStatus(TConnectionStatus Status)
        {
            // throw new NotImplementedException();
        }

        public void ClientShutdown()
        {
            _Skype.Client.Shutdown();
        }

        public IEnumerable<Contact> GetContactList()
        {
            IEnumerable<SKYPE4COMLib.User> users = _Skype.Friends.OfType<SKYPE4COMLib.User>();
            var contactList = from u in users
                              select u.ToContact();
            return contactList;
        }

        public IEnumerable<SkypeStudio.Controls.Model.Chat> GetChatList()
        {
            if (((ISkype)this._Skype).AttachmentStatus != TAttachmentStatus.apiAttachSuccess)
                return null;

           

            return Chats;
        }

        public void Dispose()
        {
            if (_Skype != null)
            {
                ((_ISkypeEvents_Event)_Skype).ConnectionStatus -= SkypeApplicationServiceConnectionStatus;
                ((_ISkypeEvents_Event)_Skype).AttachmentStatus -= SkypeApplicationServiceAttachmentStatus;
                _Skype.MessageStatus -= SkypeMessageStatusChanged;
                _Skype.OnlineStatus -= SkypeOnlineStatusChanged;

                _Skype = null;
            }
        }

        public SkypeProcessAttachStatus SkypeProcessAttachStatus
        {
            get { return (SkypeProcessAttachStatus)(int)((ISkype)_Skype).AttachmentStatus; }
        }

        private void OnContactOnlineStatusChanged(Contact c)
        {
            Action<Contact> handler = ContactOnlineStatusChanged;
            if (handler != null)
                handler(c);
        }
        private void OnMessageSent(Model.ChatMessage obj)
        {
            Action<Model.ChatMessage> handler = MessageSent;
            if (handler != null)
                handler(obj);
        }
        private void OnMessageSending(Model.ChatMessage obj)
        {
            Action<Model.ChatMessage> handler = MessageSending;
            if (handler != null)
                handler(obj);
        }

        private void OnMessageReceived(Model.ChatMessage obj)
        {
            Action<Model.ChatMessage> handler = MessageReceived;
            if (handler != null)
                handler(obj);
        }
        private void OnSkypeProcessAttachStatusChanged(SkypeProcessAttachStatus obj)
        {
            Action<SkypeProcessAttachStatus> handler = SkypeProcessAttachStatusChanged;
            if (handler != null)
                handler(obj);
        }
        public event Action<SkypeProcessAttachStatus> SkypeProcessAttachStatusChanged;


        public void OpendAddContactDialog()
        {
            _Skype.Client.OpenSearchDialog();
        }


        public void OpendSearchFriendDialog()
        {
            _Skype.Client.OpenSearchDialog();
        }


        public void OpendShareFileDialog()
        {
            // _Skype.Client.OpenFileTransferDialog();
            throw new NotImplementedException();
        }

        public void SendMessage(Contact user, string sendText)
        {
            SendMessage(user.Handle, sendText);
        }

        public void SendMessage(string handle, string sendText)
        {
            _Skype.SendMessage(handle, sendText);
        }

        public void SendMessage(Model.Chat chat, string sendText)
        {
            //SendMessage(user.Handle, sendText);
            _Skype.get_Chat(chat.ChatName).SendMessage(sendText);

        }


        public Contact CurrentUSer
        {
            get
            {
                return _Skype.CurrentUser.ToContact();
            }
        }


        public Model.Chat CreateChat(Contact contact)
        {
            if (contact == null)
                throw new ArgumentNullException("contact");

            SKYPE4COMLib.Chat skyChat = this._Skype.CreateChatWith(contact.Handle);

            Model.Chat existigChat = Chats.FirstOrDefault(o => o.ChatName == skyChat.Name);
            if (existigChat != null)
            {
                return existigChat;
            }
            else
            {

                Model.Chat chat = new SkypeStudio.Controls.Model.Chat()
                        {
                            ChatName = skyChat.Name,
                            Members = new ObservableCollection<Contact>(skyChat.Members.OfType<SKYPE4COMLib.User>().Select(o => o.ToContact())),
                            ChatMessages = new ObservableCollection<SkypeStudio.Controls.Model.ChatMessage>(skyChat.RecentMessages.OfType<SKYPE4COMLib.ChatMessage>()
                                                .Select(o => new SkypeStudio.Controls.Model.ChatMessage() { Message = o.Body, User = o.Sender.ToContact() })),
                            CurrentUser = this.CurrentUSer,
                        };

                Chats.Add(chat);
                return chat;
            }

            
        }
    }

    public static class UserExtenstion
    {
        public static Contact ToContact(this User u)
        {
            return new Contact()
                              {
                                  About = u.About,
                                  Aliases = u.Aliases,
                                  Birthday = u.Birthday,
                                  CanLeaveVoicemail = u.CanLeaveVoicemail,
                                  City = u.City,
                                  Country = u.Country,
                                  CountryCode = u.CountryCode,
                                  DisplayName = u.DisplayName,
                                  FullName = u.FullName,
                                  Handle = u.Handle,
                                  Homepage = u.Homepage,
                                  IsAuthorized = u.IsAuthorized,
                                  IsBlocked = u.IsBlocked,
                                  IsCallForwardActive = u.IsCallForwardActive,
                                  IsSkypeOutContact = u.IsSkypeOutContact,
                                  IsVideoCapable = u.IsVideoCapable,
                                  Language = u.Language,
                                  LanguageCode = u.LanguageCode,
                                  LastOnline = u.LastOnline,
                                  MoodText = u.MoodText,
                                  NumberOfAuthBuddies = u.NumberOfAuthBuddies,
                                  OnlineStatus = (OnlineStatus)(int)u.OnlineStatus,
                                  PhoneHome = u.PhoneHome,
                                  PhoneMobile = u.PhoneMobile,
                                  PhoneOffice = u.PhoneOffice,
                                  Province = u.Province,
                                  ReceivedAuthRequest = u.ReceivedAuthRequest,
                                  SpeedDial = u.SpeedDial,
                                  Timezone = u.Timezone,
                              };
        }
    }


}
